console.log('hello-ts');
// ts中的数据类型
// 01: boolean 
let a: boolean = true;
// 02: 字符串
let b: string = '123';
// 03: 数字类型
let c: number = 100
// 04: undefined
let d: undefined = undefined;
// 05: null 
let e: null = null
// 06: 数组类型
// 第一种方式: 字面量声明方式
let f: string[] = ['a', 'b', 'd',]
// 第二种方式: 泛型声明方式
let g: Array<number> = [1, 2, 3];

// 07: void 类型
// 表示没有任何类型 也是一种类型
// 一般用于函数没有返回值
function fn(): void {

}

// 08: any 类型
// 任意一种类型
// let h: any = {}

// 09: unkonwn 类型
// 未知的类型
// let i: unknown = [];


// 10：never类型
// never give up  永不放弃
// 一般不用
// 情形1
// function loop(): never {
//     while (true) { }
// }
// // 情形2
// function error(m: string): never {
//     throw new Error(m)
// }


//11. 元组类型
// 特殊的数组类型
// let j: [string, any, boolean, Array<number>] = ['1', true, false, [1, 2, 3]]

// 12. 对象类型
// let k: Object = {
//     name: '李焕英',
//     age: 20
// }

// 13: 枚举类型
// 列出了一个类型范围, 只能从该范围中取值
// enum Sex {
//     male = '男',
//     female = '女',
//     unknown = '未知'
// }

// console.log('Sex', Sex);
// let l: Sex = Sex.male
// console.log('l', l);

// 14: 联合类型
// let m: string | number | string[] = ['']


//15: symbol 类型
// 特点: 不可变且唯一的
// let sym1 = Symbol()
// let sym2 = Symbol()
// console.log(sym1 == sym2);  // fasle
// 一般用于表示对象的key 属性, 因为key就是不可变且唯一的

// let obj = {
//     [sym1]: '123'
// }

// console.log(obj[sym1]);

//  ts中的函数
// function fn1(m: string, age: number): string {
//     return `我是${m},年龄是${age}`
// }

// const fn2 = (m: string, n: number): void => {

// }


//17. ts函数的参数类型
// 01: 可选参数
// 02: 默认参数
// 03: 剩余参数

// const fn3 = (name: string = '李四', age?: number, ...arr: Array<any>): void => {
//     console.log(name, age, arr);

// };

// fn3('王五', 30, true, [123], { name: '小强' })


//18: interface
// 接口
// interface 主要用来创建一个数据类型
// enum Sex1 {
//     male = '男',
//     female = '女',
//     unknown = '未知'
// }
// interface Person {
//     name: string,
//     age: number,
//     sex: Sex1
// }

// let p: Person = {
//     name: '小丽',
//     age: 20,
//     sex: Sex1.female
// }

// console.log('p', p);

//19: interface 接口的属性的类型
// 01: 普通属性
// 02: 可选属性  可传可不传
// 03: 只读属性  不能修改

// interface Womwen {
//     readonly name: string, //
//     age?: number,
//     sex: Sex1
// }

// let fanbingbing: Womwen = {
//     name: '范冰冰',
//     sex: Sex1.female
// }
// fanbingbing.sex = Sex1.male

// console.log('fanbingbing', fanbingbing);


// 20: 接口中定义函数
// enum Sex2 {
//     boy = '男',
//     girl = '女'
// }
// interface Animal {
//     name: string,
//     age: number,
//     sex: Sex2,
//     // eat(m: string): void
//     eat: (m: string) => void
// }

// let dog: Animal = {
//     name: '旺财',
//     age: 10,
//     sex: Sex2.boy,
//     eat(m) {
//         console.log(this.name + '爱吃' + m);
//     }
// }

// console.log('dog', dog);
// dog.eat('猪肉')

// 21: 接口中的函数可以单独定义
// 使用接口定义了一个函数类型
// interface swimming {
//     (n: string): any
// }
// interface Fish {
//     name: string,
//     fn: swimming
// }

// let qingdaofu: Fish = {
//     name: '清道夫',
//     fn(n) {
//         return '吃' + n
//     }
// };

// console.log('qingdaofu', qingdaofu);

// console.log(qingdaofu.fn('垃圾'));


// 22: 可索引接口
// 定义: 一般如果该接口用来定义数组类型或对象类型, 该类型的接口叫做可索引接口

// 使用接口定义一个数组类型
// interface Arr {
//     [key: number]: any
// }

// let arr1: Arr = ['100', {}]

// // 使用接口定义对象类型
// interface Obj {
//     [key: string]: any
// }

// let user: Obj = {
//     name: '张三',
//     fn() {

//     }
// }


// 23. 接口的继承

// interface Bird {
//     name: string,
//     age: number,
//     fly: () => void
// }

// enum Gender {
//     male = '公',
//     female = '母'
// }
// interface chicken extends Bird {
//     eat(m: string): string,
//     egg: string,
//     sex: Gender
// }

// let ji: chicken = {
//     eat(m) {
//         return m
//     },
//     egg: '鸡蛋',
//     sex: Gender.female,
//     name: '昴日星官',
//     age: 20,
//     fly() {
//         console.log('能飞');

//     }
// }

// console.log(ji);


//  24. 使用接口定义额外属性(可拓展属性)
// [key: string]: any  // 没有匹配的属性都匹配这个
// interface Girl {
//     name: string,
//     age: number,
//     [key: string]: any  //
// }

// let xiaohong: Girl = {
//     name: '小红',
//     age: 18,
//     sex: '女',
//     run() {

//     }
// }


// 25: type 也可以定义数据类型
// type str = string;

// let str1: str = 'true'

// type num = number;
// let num1: num = 100;

// type Person1 = {
//     name: string,
//     age: number,
//     run(m: string): void
// }
// let p1: Person1 = {
//     name: '小明',
//     age: 20,
//     run() {

//     }
// }

// type Arr1 = Array<number | string>;
// let arr2: Arr1 = [100, 'abc']

// type FN = (m: number) => any;
// let fn4: FN = function (m) {
//     console.log(m);

// }


//26: interface 和type的区别?
// 共同点: 都可以定义数据类型
// 不同点:
// 01: interface 一般用来定义对象数据类型 , type 可以定义任意数据类型
// 02: interface 可以继承, type 不能继承;
// 03: interface 可以实现自动合并,type 不能合并, 也不能重复声明

// interface P1 {
//     name: string
// }
// interface P1 {
//     age: number
// }

// let p10: P1 = {
//     name: '小明',
//     age: 30

// }

// type P2 = {
//     name: string
// }

// type P2 = {
//     name: string
// }


// 27: 类型断言
// 错误写法:
// let student = {};
// student.name = '史鑫剑';
// student.age = 20;

// 类型断言定义: 有时候你比程序更知道该值是什么类型, 所以,类型断言,指定数据是一个什么类型,

// 正确写法
// interface Stu {
//     name: string,
//     age: number
// }
// let student = {};
// (student as Stu).name = '小明';
// (student as Stu).age = 20;


//! 表示该值为非null和 非 undefined;
// let p1 = document.querySelector('p')!; // null 或一个p元素


// 类型断言  断言p 为 HTMLParagraphElement数据类型
// console.log((p1 as HTMLParagraphElement).innerHTML);
// console.log(p1.innerHTML);

// 可选链
// let p1 = document.querySelector('p');
// console.log(p1?.innerHTML);



// 28: ts中的类

// class Boy {
//     name = '张三';
//     age = 30;
//     say() {
//         return `${this.name}说打雷收衣服了!!!!`
//     }
// }

// let sanzang = new Boy()
// console.log(sanzang);


// class Boy {
//     name: string;
//     age: number;
//     constructor(name: string, age: number) {
//         this.name = name;
//         this.age = age
//     };
//     say(m: string): string {
//         return this.name
//     }
// };

// class Student extends Boy {
//     sex: string;
//     study(): void {
//         console.log(this.name);
//     };
//     constructor(sex: string, name: string, age: number) {
//         super(name, age)
//         this.sex = sex


//     }
// }

// let xiaohua = new Student('男', '小花', 30);
// console.log(xiaohua);
// xiaohua.study()
// console.log(xiaohua.say('haha'));



// 29:类的静态属性
// 定义: 静态属性是通过类名直接可以访问的属性, 不能通过实例化对象访问
// es中的静态属性
// function Person() {
//     this.name = '张三'
// }
// let p = new Person()

// Person.sex = '男' // 称之为静态属性

// console.log(p.name);
// console.log(Person.sex);


// es6中的静态属性(不重要)

// class Men {
//     name: string;
//     static age: number;
//     constructor(name: string, age: number) {
//         this.name = name;
//         Men.age = age
//     };
//     say(m: string): string {
//         return this.name
//     }
// };

// let men = new Men('姚明', 43);

// console.log(men);
// console.log(Men.age);


// 30: 类类型接口(不重要);
// 使用一个类去实现一个接口. 接口给类进行了一个属性范围的约束
// interface Bird {
//     name?: string,
//     age: number,
//     sing(): string
// }

// class bage implements Bird {
//     age: number;
//     sing(): string {
//         return `我爱唱歌`
//     };
//     constructor(name: string, age: number) {

//         this.age = age

//     }
// }


// let xiaobage = new bage('小八哥', 5)


// 31: 抽象类
// 特点1: 一般作为父类使用, 不能被实例化
// 特点2: 抽象类中的抽象方法 不能在抽象类中写具体实现, 只能在子类中实现
// abstract class Animal {
//     name: string;
//     age: number;
//     abstract say(): void
//     constructor(name: string, age: number) {
//         this.name = name
//         this.age = age
//     }
// }

// let elephant = new Animal('大象', 10)
// console.log('elephant', elephant);

// class Cat extends Animal {
//     sex: string = '雄性';
//     constructor(name: string, age: number) {
//         super(name, age)
//     }
//     say() {
//         console.log('我喜欢吃鱼');
//     }
// }

// let xiaohuahua = new Cat('小花花', 6);
// console.log(xiaohuahua);



// 32:  泛型(重要)
//  泛型就是一个类型变量, 赋值什么类型就是什么类型
function fn10(x: number): number {
    return x
}

function fn11(x: string): string {
    return x
}


// 将上述函数合并成一个
// function fn12(x: string | number): number | string {
//     return x
// }


// 使用泛型语法合并
// T 可以理解为一个变量,  当使用时候, 传什么类型, T就表示什么类型
type scope = string | number;
function fn13<T extends scope>(x: T): T {
    return x
}
fn13(100)  // T 表示number
fn13('100') // T表示string
// fn13(true) //报错



// 33: 泛型在接口中的使用

// interface F<T> {
//     (m: T): T
// }

// let f1: F<string> = (m: string): string => {
//     return m
// }


// 34: 泛型在类中的使用
class Hero<T extends number | string | boolean>{
    nameArr: T[] = [];
    addHero(name: T) {
        this.nameArr.push(name)
    }
}


let hero = new Hero();
hero.addHero('燕双鹰')
hero.addHero('元芳')
hero.addHero(true)
hero.addHero(100)
// hero.addHero({})
console.log(hero);








